import { DocumentEventCenter } from "../base_frame/DocumentEventCenter";
import { IShaderBase } from "../base_frame/IShaderBase";
import { Keyboard } from "../base_frame/Keyboard";
import { ShaderBase } from "../base_frame/ShaderBase";
import { ShaderMgr } from "../base_frame/ShaderMgr";
import { ShaderTool } from "../base_frame/ShaderTool";
import { Vector3 } from "../base_frame/math/Vector3";

export class FogDemo extends ShaderBase implements IShaderBase {

    protected readonly VS: string =
        "attribute vec4 a_Position;\n" +
        "attribute vec4 a_Color;\n" +
        "attribute vec4 a_EyePos;\n" +

        "uniform mat4 u_MvpMatrix;\n" +
        "uniform mat4 u_ModuleMatrix;\n" +

        "varying vec4 v_Color;\n" +
        "varying float v_Distance;\n" +
        "void main(){\n" +
        "   v_Distance = distance(u_ModuleMatrix*a_Position , a_EyePos);\n" +
        "   v_Color = a_Color;\n" +
        "   gl_Position = u_MvpMatrix*a_Position;\n" +
        "}\n";

    protected readonly FS: string =
        "#ifdef GL_ES\n" +
        "precision mediump float;\n" +
        "#endif\n" +
        "uniform vec3 u_FogColor;\n" +
        "uniform vec2 u_FogDist;\n" +
        "varying float v_Distance;\n" +
        "varying vec4 v_Color;\n" +
        "void main(){\n" +
        // 这里 clamp 后面两个参数是限定范围的参数，当值超过了限定范围使用其接近的极限值作为最终值
        "   float factor = clamp((u_FogDist.y - v_Distance)/(u_FogDist.y - u_FogDist.x),0.0,1.0);\n" +
        // mix(x,y,a)  a控制混合结果 return x(1-a) +y*a  返回 线性混合的值
        "   vec3 realColor = mix(u_FogColor, v_Color.rgb, factor);\n" +
        // "   vec3 realColor = v_Color.rgb * factor + u_FogColor * (1 - factor);\n" +
        "   gl_FragColor = vec4(realColor, v_Color.a);\n" +
        "}\n"


    protected count: number;
    protected a_Position: number;
    protected a_Color: number;
    protected a_EyePos: number;

    protected u_ModuleMatrix: WebGLUniformLocation;
    protected u_FogColor: WebGLUniformLocation;
    protected u_FogDist: WebGLUniformLocation;

    protected fogColor: Vector3 = new Vector3(1.0, 0.0, 0.0);
    protected fogDist: Vector3 = new Vector3(55.0, 88.0, 0.0);
    draw(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        gl.drawElements(gl.TRIANGLES, this.count, gl.UNSIGNED_BYTE, 0);
    }

    init(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        if (!initShaders(gl, this.VS, this.FS)) return console.error("init shader fail!!");
        this.initRef(gl);
        this.count = this.initBuffer(gl);
        this.initValue(gl);
        this.fogColor.cloneTo(ShaderMgr.clearColor);
        ShaderMgr.camera.eyeVec3.setValue(25, 65, 35);
        ShaderMgr.camera.lookVec3.setValue(0.0, 2.0, 0.0);
        DocumentEventCenter.regEvent(DocumentEventCenter.keyDown, this, this.onKeyDown);

    }

    onKeyDown(ev: KeyboardEvent) {
        switch (ev.keyCode) {
            case Keyboard.A:
                if(this.fogDist.y > this.fogDist.x) this.fogDist.y -= 1;
                this.initValue(this.gl);
                break;
            case Keyboard.D:
                this.fogDist.y += 1;
                this.initValue(this.gl);
                break;
        }
    }

    initBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext): number {
        //顶点坐标
        //      L4------L5 
        //      /|       /|
        //    L0------L1  |
        //     | |     |  |
        //     | L6----|-L7 
        //     | /     | /
        //    L2------L3 
        var vertices = new Float32Array([   // Vertex coordinates
            1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1,    // v0-v1-v2-v3 front
            1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1,    // v0-v3-v4-v5 right
            1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1,    // v0-v5-v6-v1 up
            -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1,    // v1-v6-v7-v2 left
            -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,    // v7-v4-v3-v2 down
            1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1     // v4-v7-v6-v5 back
        ]);

        var colors = new Float32Array([     // Colors
            0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0,  // v0-v1-v2-v3 front
            0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4,  // v0-v3-v4-v5 right
            1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4,  // v0-v5-v6-v1 up
            1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4,  // v1-v6-v7-v2 left
            1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,  // v7-v4-v3-v2 down
            0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0   // v4-v7-v6-v5 back
        ]);

        var indices = new Uint8Array([       // Indices of the vertices
            0, 1, 2, 0, 2, 3,    // front
            4, 5, 6, 4, 6, 7,    // right
            8, 9, 10, 8, 10, 11,    // up
            12, 13, 14, 12, 14, 15,    // left
            16, 17, 18, 16, 18, 19,    // down
            20, 21, 22, 20, 22, 23     // back
        ]);

        if (!this.createBuffer(gl, vertices, this.a_Position, 3)) return -1;
        if (!this.createBuffer(gl, colors, this.a_Color, 3)) return -1;

        let buffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
        return indices.length;
    }

    protected createBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext, data: any, index: number, size: number, type: number = gl.FLOAT) {
        let buffer = gl.createBuffer();
        if (!buffer) {
            console.error("create buffer fail!!");
            return false;
        }
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
        gl.vertexAttribPointer(index, size, type, false, 0, 0);
        gl.enableVertexAttribArray(index);
        return true;
    }

    initValue(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        let eyeVec3 = ShaderMgr.camera.eyeVec3;
        gl.vertexAttrib4f(this.a_EyePos, eyeVec3.x, eyeVec3.y, eyeVec3.z,1.0);
        gl.uniformMatrix4fv(this.u_ModuleMatrix, false, this.moduleMatrix.elements);
        gl.uniform3fv(this.u_FogColor, this.fogColor.toArray());
        gl.uniform2f(this.u_FogDist, this.fogDist.x, this.fogDist.y);
        DocumentEventCenter.sendEvent(DocumentEventCenter.updateRenderFlag);

    }

    initRef(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        //@ts-ignore;
        let program = gl.program;
        this.a_Position = gl.getAttribLocation(program, "a_Position");
        this.a_Color = gl.getAttribLocation(program, "a_Color");
        this.a_EyePos = gl.getAttribLocation(program, "a_EyePos");

        this.u_ModuleMatrix = gl.getUniformLocation(program, "u_ModuleMatrix");
        this.u_FogColor = gl.getUniformLocation(program, "u_FogColor");
        this.u_FogDist = gl.getUniformLocation(program, "u_FogDist");
    }

    inputBlur(text: string): void {
        if(text){
            ShaderTool.setProperty(text, this);

        }
    }

}